home *** CD-ROM | disk | FTP | other *** search
/ PC-Blue - MS DOS Public Domain Library / PC-Blue MS-DOS Public Domain Library - NYACC.iso / vol270 / hsort.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-12-16  |  5.1 KB  |  179 lines

  1. /*    hsort - general purpose heapsort 
  2.  
  3.     Author...
  4.         Copyright (c) 1985  James R. Van Zandt
  5.  
  6.         All rights reserved.
  7.         This program may be copied for personal, non-profit use only.
  8.  
  9.         Based on algorithms by Jon Bentley [Communications of the ACM v
  10.         28 n 3 p 245 (Mar 85) and v 28 n 5 p 456 (May 85)], and the
  11.         sort interface routines by Allen I.  Holub [Dr.  Dobb's Journal
  12.         #102 (Apr 85)].
  13.  
  14.     Usage...
  15.  
  16.         Including a #define for DEBUG will make this file a stand-alone
  17.         program which sorts argv and prints the result, along with the
  18.         heap at the intermediate stages.  This is instructive if you
  19.         want to see how the heap sort works.  #defining DEBUG2 will
  20.         also print results of comparisons.
  21.  
  22.     Notes...
  23.         This routine sorts N objects in worst-case time proportional to
  24.         N*log(N).  The heapsort was discovered by J.  W.  J.  Williams
  25.         [Communications of the ACM v 7 p 347-348 (1964)] and is
  26.         discussed by D.  E.  Knuth [The Art of Computer Programming,
  27.         Volume 3: Sorting and Searching, Addison-Wesley, Reading,
  28.         Mass., 1973, section 5.2.3].
  29.  
  30.         This algorithm depends on a portion of an array having the
  31.         "heap" property.  The array X has the property heap[L,U] if:
  32.  
  33.             for all      L, i, and U
  34.             such that    2L <= i <= U
  35.             we have      X[i div 2] <= X[i]
  36.         
  37.         sift_down enlarges the heap: It accepts an array with heap[L+1,U]
  38.         and returns an array with heap[L,U].
  39. */
  40.  
  41. typedef int (*PFI)();        /* pointer to a function returning int    */
  42. static PFI Comp;            /* pointer to comparison routine        */
  43. static int Width;            /* width of an object in bytes            */
  44. static char *Base;            /* pointer to element [-1] of array        */
  45. static char *a, *b, tmp;    /* temporaries for exchanges            */
  46.  
  47. #ifdef DEBUG
  48. int Exchanges=0, Comparisons=0;
  49. #endif
  50.  
  51. /*--------------------------------------------------------------------------*/
  52. int argvcmp(s1p,s2p) char **s1p,**s2p;
  53. {
  54.     /*    Comparison routine for sorting an argv like list of pointers to
  55.         strings.  Just remove one level of indirection and call strcmp
  56.         to do the comparison                                                */
  57.  
  58. #ifdef DEBUG
  59.     Comparisons++;
  60. #endif
  61. #ifdef DEBUG2
  62.     register int rval;
  63.     rval=strcmp(*s1p,*s2p);
  64.     printf("   argvcmp(<%s><%s>) = %d\n",*s1p,*s2p,rval);
  65.     return (rval);
  66. #else
  67.     return (strcmp(*s1p,*s2p));
  68. #endif
  69. }
  70.  
  71. hsort(base,nel,width,compare)
  72. char *base;
  73. int    nel,width;
  74. int    (*compare)();
  75. {
  76. static int i,j,n,stop;
  77.     /*    Perform a heap sort on an array starting at base.  The array is
  78.         nel elements large and width is the size of a single element in
  79.         bytes.  Compare is a pointer to a comparison routine which will
  80.         be passed pointers to two elements of the array.  It should
  81.         return a negative number if the left-most argument is less than
  82.         the rightmost, 0 if the two arguments are equal, a positive
  83.         number if the left argument is greater than the right.  (That
  84.         is, it acts like a "subtract" operator.) If compare is 0 then
  85.         the default comparison routine, argvcmp (which sorts an
  86.         argv-like array of pointers to strings), is used.                    */
  87.  
  88. #ifdef DEBUG
  89.     static int ii;
  90.     printf("Sorting %d element array of %d byte elements at 0x%x\n",
  91.         nel,width,base);
  92.     printf("Comparison routine at 0x%x. Unsorted list:\n",compare);
  93.     ptext(1,nel,base);
  94.     for ( ii=1 ; ii<=nel ; ii++ ) printf("[%d]     ",ii);
  95.     printf("\n");
  96. #endif
  97.     Width=width;
  98.     Comp=(compare==(PFI)0) ? &argvcmp : compare ;
  99.     n=nel*Width;
  100.     Base=base-Width;
  101.     for (i=(n/Width/2)*Width; i>=Width; i-=Width) sift_down(i,n);
  102. #ifdef DEBUG
  103.     printf("Heap constructed\n");
  104.     for ( ii=1 ; ii<=nel ; ii++ ) printf("[%d]     ",ii);
  105.     printf("\n");
  106. #endif
  107.     stop=Width+Width;
  108.     for (i=n; i>=stop; )
  109.         {for (b=base, a=Base+i, j=Width ; j-- ; )
  110.             {tmp = *b; *b++ = *a; *a++ = tmp;
  111.             }
  112. #ifdef DEBUG
  113.         Exchanges++;
  114. #endif
  115.         sift_down(Width,i-=Width);
  116.         }
  117.  
  118. #ifdef DEBUG
  119.     printf("\nSort complete, list is:\n");
  120.     ptext(1,nel,base);
  121.     printf("%d comparisons and %d exchanges were performed \n",
  122.     Comparisons,Exchanges);
  123. #endif
  124. }
  125.  
  126. /*---------------------------------------------------------------------------*/
  127. static sift_down(L,U) int L,U;
  128. /*    pre: heap(L+1,U)        */
  129. {    int c,count;
  130.  
  131. #ifdef DEBUG
  132.     int i1;
  133.     i1=L;
  134. #endif
  135.     while(1)
  136.         {c=L+L;
  137.         if(c>U) break;
  138.         if( (c+Width <= U) && ((*Comp)(Base+c+Width,Base+c)>0) ) c+= Width;
  139.         if ((*Comp)(Base+L,Base+c)>=0) break;
  140.         for(b=Base+L,a=Base+c,count=Width; count-- ; )
  141.             {tmp=*b; *b++ = *a; *a++ = tmp;
  142.             }
  143. #ifdef DEBUG
  144.         Exchanges++;
  145. #endif
  146.         L=c;
  147.         }
  148. #ifdef DEBUG
  149.     ptext(i1/2,U/2,Base+Width);
  150. #endif
  151. /*    post: heap(L,U)            */
  152. }
  153.  
  154. /*--------------------------------------------------------------------------*/
  155. /*        Test routine for hsort, compiled if DEBUG is #defined                */
  156.  
  157. #ifdef DEBUG
  158. static ptext( start, end, argv)
  159. int start,end;
  160. char **argv;
  161. {
  162.     /*    Print out argv, one element per line    */
  163.  
  164.     register int i;
  165.     for (i=1; i<start; i++) {printf("        "); argv++;}
  166.     for ( i=start ; i<=end ; i++ ) printf("%-8s",*argv++);
  167.     printf("\n");
  168. }
  169.  
  170. main(argc,argv) int argc; char **argv;
  171. {    
  172.     /*    Test routine for hsort.  Sorts argv (less the first element).    */
  173.  
  174.     hsort(++argv,--argc,sizeof(PFI),0);
  175. }
  176.  
  177. #endif
  178.  
  179.